#include "stdafx.h"
#include "bbAddon.h"

using namespace std;


/*======================================================================*/
/*						 Linked List */
/*======================================================================*/

/* ***********
 * PRIVATE *
 ************/

struct TList{
	TLink* _head;
	TLink* _tail;
};

struct TLink{
	TList* _list;
	string _data;
	TLink* _next;
	TLink* _prev;
};

TLink* __NULL_LINK = new TLink();
int __Debug_COUNTLINKS	= 0;

inline void Unlink(TLink* lnk)
{
	TList* l = lnk->_list;
	
	if (lnk==l->_head)
	{
		if (lnk==l->_tail)
		{
			l->_head=__NULL_LINK;
			l->_tail=__NULL_LINK;
		}
		else
		{
			l->_head=lnk->_next;
			l->_head->_prev=__NULL_LINK;
		};
	}
	else
	{
		if (lnk==l->_tail)
		{
			l->_tail=l->_tail->_prev;
			l->_tail->_next=__NULL_LINK;
		}
		else
		{
			lnk->_next->_prev=lnk->_prev;
			lnk->_prev->_next=lnk->_next;
		};
	};
	lnk->_next=__NULL_LINK;
	lnk->_prev=__NULL_LINK;
};

/* ********
 * PUBLIC *
 **********/
BBAEXP int BBACALL DebugCountLinks (){return __Debug_COUNTLINKS;};

BBAEXP void BBACALL DeleteList (TList * list)
{
	while (list->_head!=__NULL_LINK)
	{
		TLink* temp(list->_head);
		list->_head=list->_head->_next;
		delete temp;
		__Debug_COUNTLINKS--;
	};
	delete list;
};

BBAEXP void BBACALL DeleteLink (TLink * lnk){Unlink(lnk);delete lnk;__Debug_COUNTLINKS--;};

BBAEXP void BBACALL SetLinkValue (TLink* lnk, const char* datas){lnk->_data=datas;};

BBAEXP int BBACALL NewList()
{
	TList* list		=	new TList();
	list->_head		=	__NULL_LINK;
	list->_tail		=	__NULL_LINK;
	return TobbObject(list);
};

BBAEXP int BBACALL ListInsertAfter(TLink* lnk, TLink* after)
{
	if (lnk->_list!=after->_list) return 0;
	Unlink(lnk);
	TList* l=after->_list;
	if (after==l->_tail)
	{
		lnk->_next=__NULL_LINK;
		lnk->_prev=after;
		after->_next=lnk;
		l->_tail=lnk;
	}
	else
	{
		lnk->_prev=after;
		after->_next->_prev=lnk;
		lnk->_next=after->_next;
		after->_next=lnk;
	};
	return 1;
};
BBAEXP int BBACALL ListInsertBefore(TLink* lnk, TLink* before)
{
	if (lnk->_list!=before->_list) return 0;
	Unlink(lnk);
	TList* l=before->_list;
	if (before==l->_head)
	{
		lnk->_prev=__NULL_LINK;
		lnk->_next=before;
		before->_prev=lnk;
		l->_head=lnk;
	}
	else
	{
		lnk->_next=before;
		before->_prev->_next=lnk;
		lnk->_prev=before->_prev;
		before->_prev=lnk;
	};

	return 1;
};

BBAEXP int BBACALL ListAddLast(TList* list, char* pValue)
{
	TLink* lnk		=	new TLink();
	lnk->_data		=	pValue;
	lnk->_list		=	list;
	
	if (list->_head==__NULL_LINK)
	{
		list->_head	=	lnk;
		lnk->_prev	=	__NULL_LINK;
	}
	else
	{
		list->_tail->_next=lnk;
		lnk->_prev	=	list->_tail;
	};
	list->_tail		=	lnk;
	lnk->_next		=	__NULL_LINK;
	__Debug_COUNTLINKS++;
	return TobbObject(lnk);
};

BBAEXP int BBACALL ListAddFirst(TList* list, const char* pValue)
{
	TLink* lnk		=	new TLink();
	lnk->_data		=	pValue;
	lnk->_list		=	list;
	
	if (list->_tail==__NULL_LINK)
	{
		list->_tail	=	lnk;
		lnk->_next	=	__NULL_LINK;
	}
	else
	{
		list->_head->_prev=lnk;
		lnk->_next	=	list->_head;
	};
	list->_head		=	lnk;
	lnk->_prev		=	__NULL_LINK;
	__Debug_COUNTLINKS++;
	return TobbObject(lnk);
};

BBAEXP int BBACALL ListContains(TList* list, const char* value)
{
	if (list->_head==__NULL_LINK) return 0;
	TLink* l = list->_head;
	while (l!=__NULL_LINK)
	{
		if (l->_data.compare(value)==0) return TobbObject(l);
		l=l->_next;
	};
	return 0;
};

BBAEXP const int BBACALL ListIsEmpty(const TList* list)	{return (list->_head==__NULL_LINK);};

BBAEXP const int BBACALL FirstLink(const TList* list)
	{if (list->_head==__NULL_LINK){return 0;};return TobbObject(list->_head);};
BBAEXP const int BBACALL LastLink(const TList* list)
	{if (list->_head==__NULL_LINK){return 0;};return TobbObject(list->_tail);};

BBAEXP const int BBACALL AfterLink(const TLink* link){if (link==link->_list->_tail){return 0;};return TobbObject(link->_next);};
BBAEXP const int BBACALL BeforeLink(const TLink* link){if (link==link->_list->_head){return 0;};return TobbObject(link->_prev);};

BBAEXP int BBACALL len(const char* a){return strlen(a);};
BBAEXP int BBACALL LinkCompare(const TLink* l1, const TLink* l2){return l1->_data.compare(l2->_data);};
BBAEXP int BBACALL StrCompare(const char* a, const char* b){return strcmp(a,b);};
BBAEXP const char* BBACALL LinkValue(const TLink* link){return link->_data.c_str();};

BBAEXP int BBACALL SwapLinks(TLink* l1, TLink* l2)
{
	TList*l=l1->_list;
	if (l2->_list!=l){return 0;};
	if (l1==l2){return 0;};
	TLink* l1n=l1->_next;
	TLink* l1p=l1->_prev;
	if (l1n==__NULL_LINK)
	{
		if(l1p==__NULL_LINK)
		{
			return 0;
		}
		else
		{
			Unlink(l1);ListInsertAfter(l1,l2);
			Unlink(l2);ListInsertAfter(l2,l1p);
		};
	}
	else
	{
		Unlink(l1);ListInsertAfter(l1,l2);
		Unlink(l2);ListInsertBefore(l2,l1n);
	};
	return 1;
};

int SortListDESC2(TList* list)
{
	bool done=false;

	while (done==false)
	{
		done=true;
		TLink* l1=list->_tail->_prev;
		TLink* l2;
		
		while (l1!=__NULL_LINK)
		{
			l2=l1->_prev;
			
			TLink* l3=l1->_next;
			TLink* l4;
			while (l3!=__NULL_LINK)
			{
				l4=l3->_next;
				if (LinkCompare(l1,l3)<0)
				{
					ListInsertAfter(l1,l3);
					done=false;
				};
				l3=l4;
			};
			l1=l2;
		};
	};
	return 1;
};

int SortListDESC(TList* list)
{
	bool done=false;

	while (done==false)
	{
		done=true;
		TLink* l1=list->_head->_next;
		TLink* l2;
		
		while (l1!=__NULL_LINK)
		{
			l2=l1->_next;
			
			TLink* l3=l1->_prev;
			TLink* l4;
			while (l3!=__NULL_LINK)
			{
				l4=l3->_prev;
				if (LinkCompare(l1,l3)>0)
				{
					ListInsertBefore(l1,l3);
					done=false;
				};
				l3=l4;
			};
			l1=l2;
		};
	};
	return 1;
};
int SortListASC(TList* list)
{
	bool done=false;

	while (done==false)
	{
		done=true;
		TLink* l1=list->_head->_next;
		TLink* l2;
		
		while (l1!=__NULL_LINK)
		{
			l2=l1->_next;
			
			TLink* l3=l1->_prev;
			TLink* l4;
			while (l3!=__NULL_LINK)
			{
				l4=l3->_prev;
				if (LinkCompare(l1,l3)<0)
				{
					ListInsertBefore(l1,l3);
					done=false;
				};
				l3=l4;
			};
			l1=l2;
		};
	};
	return 1;
};

BBAEXP int BBACALL SortList(TList* list, int sens)
{
	if (list->_head==list->_tail) return 0;
	if (sens<0) return SortListDESC(list);
	// int res=SortListASC(list);
	// if (res>0) return SortListASC(list);
	// return res;
	return SortListASC(list);
};
